//Learned：
//1. 巧妙利用孙子进程进行托孤

#include "log.hpp"
#include "singleton.hpp"
#include "Daemon.hpp"
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <signal.h>
#include <string>
#include <vector>
#include <string.h>
#include <iostream>

#define SIZE 1024
using std::string;
using std::vector;
using std::cout;
using std::endl;

const int DefaultPort = 8080;
const string DefaultIp = "0.0.0.0";

enum
{
    SOCKERR = 1,
    BINDERR,
    LISTENERR
};

class TcpServer
{
public:
    void Init()
    {
        Daemon();
        log.Enable(OneFile);
        //1.获取socketfd
        if((_socketfd = socket(AF_INET,SOCK_STREAM,0)) < 0)
        {
            log(Fatal,"socket error, errno is %d, error messsage: %s",errno,strerror(errno));
            exit(SOCKERR);
        }
        log(Info,"socketfd create successfully, socketfd is: %d", _socketfd);

        int opt = 1;
        setsockopt(_socketfd, SOL_SOCKET, SO_REUSEADDR|SO_REUSEPORT, &opt, sizeof(opt)); // 防止偶发性的服务器无法进行立即重启

        //2.初始化结构体字段
        sockaddr_in local;
        local.sin_family = AF_INET;
        local.sin_port = htons(_port);
        //local.sin_addr.s_addr = inet_aton(_ip.c_str(),&(local.sin_addr));     //???
        //local.sin_addr.s_addr = inet_addr(_ip.c_str());
        local.sin_addr.s_addr = INADDR_ANY;

        //3.绑定socket
        if(bind(_socketfd,(sockaddr*)&local,sizeof(local)) < 0)
        {
            log(Fatal,"bind error, errno is %d, error messsage: %s",errno,strerror(errno));
            exit(BINDERR);
        }
        log(Info,"bind successfully, messsage: %s",strerror(errno));

        //4.监听
        if(listen(_socketfd,10) < 0)        //会阻塞吗？ --> 不会！这里可以理解为进入一种“状态”，来准备接受(accept)可能到来的连接
        {
            log(Fatal,"listen error, errno is %d, error messsage: %s",errno,strerror(errno));
            exit(LISTENERR);
        }
        log(Info,"listen successfully,messsage: %s",strerror(errno));
    }

    void Start()
    {
        //daemon(0,0);
        signal(SIGPIPE,SIG_IGN);
        //SingleProcessRun();
        //MultiProcessRun();
        //MultiThreadRun();
        ThreadPoolRun();
    }


    TcpServer(int port = DefaultPort, const string& ip = DefaultIp)
    :_socketfd(0),_port(port),_ip(ip)
    {
        pthread_mutex_init(&_lock,0);
    }
    ~TcpServer()
    {
        pthread_mutex_destroy(&_lock);
    }
private:

    /**Start 内的四种版本*/
    //version 1：单进程版
    void SingleProcessRun()
    {
        while(1)
        {
            sockaddr_in client;
            socklen_t len = sizeof(client);
            int newsock = accept(_socketfd,(sockaddr*)(&client),&len);        //newsock可能会有很多，注定了一定要打一个循环！
            if(newsock < 0)
            {
                log(Error,"accept errore! errno is %d, error messsage: %s",errno,strerror(errno));
            }
            log(Info,"accept successfully, newsock is %d, message: %s",newsock,strerror(errno));

            cout << "connected by [ip:" << client.sin_addr.s_addr << "]"  << "[port:" << client.sin_port << "]" << endl;

            //提供服务
            char buffer[SIZE] = {0};
            while(1)
            {
                memset(buffer,0,sizeof(buffer));
                cout << "[ip:" << client.sin_addr.s_addr << "]" << "says: ";
                if(0 >= read(newsock,buffer,SIZE))
                {
                    break;
                }
                cout << buffer << endl;


                // string msg = "server echo# " + string(buffer);
                // write(newsock,msg.c_str(),msg.size());            
            }            
        }        
    }

    //version 2：多进程版
    //一般来说，服务器启动了就不会退，故等待子进程放在析构不太现实！
    //解决方案：非阻塞轮询；
    //重要细节：创建子进程后需要关闭原先的文件描述符（子进程拷贝了一份不用担心），否则父进程的fd就会越用越少！子进程最好也把拷贝来的监听fd关了
    void MultiProcessRun()
    {
        while(1)
        {
            sockaddr_in client;
            socklen_t len = sizeof(client);
            int newsock = accept(_socketfd,(sockaddr*)(&client),&len); 
            if(newsock < 0)
            {
                log(Error,"accept error! errno is %d, error messsage: %s",errno,strerror(errno));
            }
            log(Info,"accept successfully, newsock is %d, message: %s",newsock,strerror(errno));

            cout << "connected by [ip:" << client.sin_addr.s_addr << "]"  << "[port:" << client.sin_port << "]" << endl;

            //提供服务 --> 交给子进程！
            pid_t pid = fork();
            if(pid < 0)
            {
                log(Error,"fork error! errno is %d, error messsage: %s",errno,strerror(errno));
            }
            else if(pid == 0)       
            {
                //son do...
                close(_socketfd);
                pid_t ppid = fork();
                if(ppid > 0)    //子进程直接退出，然后托孤
                {
                    exit(0);
                }

                //grandson do...
                char buffer[SIZE] = {0};
                while(1)
                {
                    memset(buffer,0,sizeof(buffer));
                    cout << "[ip:" << client.sin_addr.s_addr << "]" << "says: ";
                    if(0 >= read(newsock,buffer,SIZE))
                    {
                        exit(0);
                    }
                    cout << buffer << endl;
                    // string msg = "server echo# " + string(buffer);
                    // write(newsock,msg.c_str(),msg.size());            
                } 
            }

            //father do...
            close(newsock);
            waitpid(pid,0,0);
        }   
    }

    //version 3：多线程版
    static void* Routine(void* arg)
    {
        TcpServer* server = static_cast<TcpServer*>(arg);
        while(1)
        {
            sockaddr_in client;
            socklen_t len = sizeof(client);

            int newsock = accept(server->_socketfd,(sockaddr*)(&client),&len);        
            if(newsock < 0)
            {
                log(Error,"accept errore! errno is %d, error messsage: %s",errno,strerror(errno));
            }
            log(Info,"accept successfully, newsock is %d, message: %s",newsock,strerror(errno));

            cout << "connected by [ip:" << client.sin_addr.s_addr << "]"  << "[port:" << client.sin_port << "]" << endl;

            //提供服务
            char buffer[SIZE] = {0};
            while(1)
            {
                memset(buffer,0,sizeof(buffer));
                if(0 >= read(newsock,buffer,SIZE))
                {
                    break;
                }
                cout << "[ip:" << client.sin_addr.s_addr << "]" << "says: ";
                cout << buffer << endl;         
            }    
        }  
    }
    void MultiThreadRun()
    {
        vector<pthread_t> tids;
        for(int i = 0; i < 5; i++)
        {
            pthread_t tid;
            pthread_create(&tid,0,Routine,this);
            tids.push_back(tid);
        }

        for(int i = 0; i < 5; i++)
        {
            pthread_join(tids[i],0);
        }
    }

    //version 4：线程池版
    void ThreadPoolRun()
    {
        ThreadPool<Task>* tp = ThreadPool<Task>::GetInstance();
        tp->Start();    //记得启动线程池
        while(1)
        {
            sockaddr_in client;
            socklen_t len = sizeof(client);

            int newsock = accept(_socketfd,(sockaddr*)(&client),&len);        
            if(newsock < 0)
            {
                log(Error,"accept errore! errno is %d, error messsage: %s",errno,strerror(errno));
            }
            log(Info,"accept successfully, newsock is %d, message: %s",newsock,strerror(errno));
            cout << "connected by [ip:" << string (inet_ntoa(client.sin_addr)) << "]"  << "[port:" << client.sin_port << "]" << endl;

            //提供服务
            Task t(newsock, &client);
            tp->Push(t);
        }  
    }


    int _socketfd;
    int _port;
    string _ip;
    pthread_mutex_t _lock;
};
